package main

import (
	"fmt"
	"gorm.io/driver/mysql"
	"gorm.io/gorm"
	"gorm.io/gorm/logger"
	"gorm.io/gorm/schema"
	"log"
	"os"
	"sync"
	"time"
)

type BaseModel struct {
	ID        int32          `gorm:"primary_key;comment:ID" json:"id"`
	CreatedAt time.Time      `gorm:"column:add_time;comment:创建时间" json:"-"`
	UpdatedAt time.Time      `gorm:"column:update_time;comment:更新时间" json:"-"`
	DeletedAt gorm.DeletedAt `gorm:"comment:删除时间" json:"-"`
	IsDeleted bool           `gorm:"comment:是否删除" json:"-"`
}
type Inventory struct {
	BaseModel
	Goods   int32 `gorm:"type:int;index;comment:商品id"`
	Stocks  int32 `gorm:"type:int;comment:仓库"`
	Version int32 `gorm:"type:int;comment:分布式锁-乐观锁"`
}

var DB *gorm.DB

func InitDB() {

	dsn := fmt.Sprintf("%s:%s@tcp(%s:%d)/%s?charset=utf8mb4&parseTime=True&loc=Local",
		"root", "123456", "localhost", 3306, "mxshop_order_srv2")
	newLogger := logger.New(
		log.New(os.Stdout, "\r\n", log.LstdFlags), // io writer（日志输出的目标，前缀和日志包含的内容——译者注）
		logger.Config{
			SlowThreshold: time.Second, // 慢 SQL 阈值
			//LogLevel:      logger.Info, // 日志级别
			LogLevel: logger.Silent, // 日志级别
			//IgnoreRecordNotFoundError: true,        // 忽略ErrRecordNotFound（记录未找到）错误
			Colorful: true, // 禁用彩色打印
		},
	)
	// 参考 https://github.com/go-sql-driver/mysql#dsn-data-source-name 获取详情
	var err error
	DB, err = gorm.Open(mysql.Open(dsn), &gorm.Config{
		NamingStrategy: schema.NamingStrategy{
			SingularTable: true,
		},
		Logger: newLogger,
	})
	if err != nil {
		panic(err)
	}
}

func main() {
	InitDB()
	gNum := 20
	var Num int32 = 1
	var wg sync.WaitGroup
	wg.Add(gNum)
	for i := 0; i < gNum; i++ {
		go func() {
			defer wg.Done()
			//tx := DB.Begin()
			for {
				var inv Inventory
				//fmt.Println("开始获取锁")
				if result := DB.Where(&Inventory{Goods: 421}).First(&inv); result.RowsAffected == 0 {
					panic("库存不存在")
				}
				if inv.Stocks < Num {
					panic("库存不足")
				}
				//update inventory set stocks = stocks-1,version=version+1 where goods=goods and version=version
				inv.Stocks -= Num
				//if result := DB.Model(&model.Inventory{}).Select("Stocks", "Version").Where("goods = ? and version = ?", int32(421), inv.Version).Updates(model.Inventory{Stocks: inv.Stocks, Version: inv.Version + 1}); result.RowsAffected == 0 {
				//	fmt.Println("扣减失败 - 重试")
				//} else {
				//	fmt.Println("扣减成功")
				//	break
				//}
			}

		}()
	}
	wg.Wait()
}
